//
//  CrushView.cpp
//  FruitCrush
//
//  Created by gaoyu on 15/7/19.
//
//

#include "CrushView.h"
#include "CrushUnitSprite.h"
#include "BadStateUnitSprite.h"
#include "CombosTextView.h"
#include "MusicController.h"

#define MATRIX_WIDTH (9)
#define MATRIX_HEIGHT (6)
#define SUSHI_GAP (1)
#define DROP_HEIGHT   100
#define BG_Y_PAD      -5
#define SUCK_BLOOD_TIME   (5)
#define SUCK_BLOOD_NUM    (5)
#define BOMB_OUT_PERCENT  (50)

typedef enum {
    ZBg = 0,
    ZBadUnit,
    ZCrushUnit,
    ZBadUnitUp,
    ZColorSprite,
    ZStar,
    ZMax,


} ZIndex;

CrushView::CrushView()
: spriteSheet(NULL)
, m_matrix(NULL)
, m_width(0)
, m_height(0)
, m_matrixLeftBottomX(0)
, m_matrixLeftBottomY(0)
, m_isNeedFillVacancies(false)
, m_isAnimationing(true)//start with drop animation
, m_isTouchEnable(true)
, m_srcSushi(NULL)
, m_destSushi(NULL)
, m_allTargetSushi(NULL)
, m_movingVertical(true)//drop animation is vertical
, m_crushType(0)
, m_isPause(false)
, spriteSheetBad(NULL)
, m_matrix_bad(NULL)
, m_suckNum(0)
, m_badStateLastTime(0)
, spriteSheetBadUp(NULL)
, m_matrix_bad_up(NULL)
, spriteSheetProtectCover(NULL)
, m_matrix_protect_cover(NULL)
, spriteSheetBlank(NULL)
, m_matrix_blank(NULL)
, m_needCreateJelly(0)
, m_combosNum(0)
, m_bombNum(0)
, m_isCoverNeedClose(false)
{
}

CrushView::~CrushView()
{
    if (m_matrix) {
        free(m_matrix);
    }

    if(m_matrix_bad){
    	free(m_matrix_bad);
    }

    if(m_matrix_bad_up){
    	free(m_matrix_bad_up);
    }

    if(m_matrix_protect_cover){
    	free(m_matrix_protect_cover);
    }
}

bool CrushView::init()
{
    if (!Layer::init()) {
        return false;
    }

    auto level1bg = Sprite::create("level1Bg.png");
    level1bg->setAnchorPoint(Vec2::ZERO);
    level1bg->setPosition(Point(0,BG_Y_PAD));
    this->addChild(level1bg,ZBg);
    
    // init spriteSheet
    SpriteFrameCache::getInstance()->addSpriteFramesWithFile("Unit.plist");
    spriteSheet = SpriteBatchNode::create("Unit.pvr.ccz");
    addChild(spriteSheet,ZCrushUnit);
    
    //add for bad state
    spriteSheetBad = SpriteBatchNode::create("Unit.pvr.ccz");
    addChild(spriteSheetBad,ZBadUnit);

    spriteSheetBadUp = SpriteBatchNode::create("Unit.pvr.ccz");
    addChild(spriteSheetBadUp,ZBadUnitUp);

    spriteSheetProtectCover = SpriteBatchNode::create("Unit.pvr.ccz");
    addChild(spriteSheetProtectCover,ZBadUnitUp);

    spriteSheetBlank = SpriteBatchNode::create("Unit.pvr.ccz");
    addChild(spriteSheetBlank,ZBadUnitUp);

    // Yes, you can load this value from other module.
    m_width = MATRIX_WIDTH;
    m_height = MATRIX_HEIGHT;
    
    // init position value
    m_matrixLeftBottomX = (CRUSH_VIEW_WIDTH - CrushUnitSprite::getContentWidth() * m_width - (m_width - 1) * SUSHI_GAP) / 2;
    m_matrixLeftBottomY = 0;
    int arraySize = sizeof(CrushUnitSprite *) * m_width * m_height;
    m_matrix = (CrushUnitSprite **)malloc(arraySize);
    memset((void*)m_matrix, 0, arraySize);
    //add for matrix init
    int arraySizeBad = sizeof(BadStateUnitSprite *) * m_width * m_height;
    m_matrix_bad = (BadStateUnitSprite **)malloc(arraySizeBad);
    memset((void*)m_matrix_bad, 0, arraySizeBad);
    
    int arraySizeBadUp = sizeof(BadStateUnitSprite *) * m_width * m_height;
    m_matrix_bad_up = (BadStateUnitSprite **)malloc(arraySizeBadUp);
    memset((void*)m_matrix_bad_up, 0, arraySizeBad);

    int arraySizeProtectCover = sizeof(BadStateUnitSprite *) * m_width * m_height;
    m_matrix_protect_cover = (BadStateUnitSprite **)malloc(arraySizeProtectCover);
    memset((void*)m_matrix_protect_cover, 0, arraySizeProtectCover);

    int arraySizeBlank = sizeof(BadStateUnitSprite *) * m_width * m_height;
    m_matrix_blank = (BadStateUnitSprite **)malloc(arraySizeBlank);
    memset((void*)m_matrix_blank, 0, arraySizeBlank);

    scheduleUpdate();
    
    // bind touch event
    auto touchListener = EventListenerTouchOneByOne::create();
    touchListener->onTouchBegan = CC_CALLBACK_2(CrushView::onTouchBegan, this);
    touchListener->onTouchMoved = CC_CALLBACK_2(CrushView::onTouchMoved, this);
    _eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
    return true;
}

CrushUnitSprite *CrushView::sushiOfPoint(Point *point)
{
    CrushUnitSprite *sushi = NULL;
    Rect rect = Rect(0, 0, 0, 0);
    
    for (int i = 0; i < m_height * m_width; i++) {
        sushi = m_matrix[i];
        if (sushi) {
            rect.origin.x = sushi->getPositionX() - (sushi->getContentSize().width / 2);
            rect.origin.y = sushi->getPositionY() - (sushi->getContentSize().height / 2);
            rect.size = sushi->getContentSize();
            if (rect.containsPoint(*point)) {
                return sushi;
            }
        }
    }
    
    return NULL;
}

Vec2 CrushView::touchLocationFix(Vec2 location)
{
    
    return Point(location.x - this->getPosition().x,location.y - this->getPosition().y);
}

bool CrushView::onTouchBegan(Touch *touch, Event *unused)
{
    if(m_isPause) return true;
    m_srcSushi = NULL;
    m_destSushi = NULL;
    if (m_isTouchEnable) {
        auto location = touchLocationFix(touch->getLocation());
        m_srcSushi = sushiOfPoint(&location);
    }
    return m_isTouchEnable;
}

void CrushView::onTouchMoved(Touch *touch, Event *unused)
{
    if (!m_srcSushi || !m_isTouchEnable || m_isPause) {
        return;
    }
    


    int row = m_srcSushi->getRow();
    int col = m_srcSushi->getCol();
    
    if(isHandByMonster(row,col)) return;

    auto location = touchLocationFix(touch->getLocation());
    auto halfSushiWidth = m_srcSushi->getContentSize().width / 2;
    auto halfSushiHeight = m_srcSushi->getContentSize().height / 2;
    
    auto  upRect = Rect(m_srcSushi->getPositionX() - halfSushiWidth,
                        m_srcSushi->getPositionY() + halfSushiHeight,
                        m_srcSushi->getContentSize().width,
                        m_srcSushi->getContentSize().height);
    
    if (upRect.containsPoint(location)) {
        row++;
        if(isHandByMonster(row,col)) return;
        if (row < m_height) {
            m_destSushi = m_matrix[row * m_width + col];
        }
        m_movingVertical = true;
        swapSushi();

        return;
    }
    
    auto  downRect = Rect(m_srcSushi->getPositionX() - halfSushiWidth,
                          m_srcSushi->getPositionY() - (halfSushiHeight * 3),
                          m_srcSushi->getContentSize().width,
                          m_srcSushi->getContentSize().height);
    
    if (downRect.containsPoint(location)) {
        row--;
        if(isHandByMonster(row,col)) return;
        if (row >= 0) {
            m_destSushi = m_matrix[row * m_width + col];
        }
        m_movingVertical = true;
        swapSushi();

        return;
    }
    
    auto  leftRect = Rect(m_srcSushi->getPositionX() - (halfSushiWidth * 3),
                          m_srcSushi->getPositionY() - halfSushiHeight,
                          m_srcSushi->getContentSize().width,
                          m_srcSushi->getContentSize().height);
    
    if (leftRect.containsPoint(location)) {
        col--;
        if(isHandByMonster(row,col)) return;
        if (col >= 0) {
            m_destSushi = m_matrix[row * m_width + col];
        }
        m_movingVertical = false;
        swapSushi();

        return;
    }
    
    auto  rightRect = Rect(m_srcSushi->getPositionX() + halfSushiWidth,
                           m_srcSushi->getPositionY() - halfSushiHeight,
                           m_srcSushi->getContentSize().width,
                           m_srcSushi->getContentSize().height);
    
    if (rightRect.containsPoint(location)) {
        col++;
        if(isHandByMonster(row,col)) return;
        if (col < m_width) {
            m_destSushi = m_matrix[row * m_width + col];
        }
        m_movingVertical = false;
        swapSushi();

        return;
    }
    
    // not a useful movement
}


bool CrushView::swapSushi()
{
    m_isAnimationing = true;
    m_isTouchEnable = false;
    if (!m_srcSushi || !m_destSushi
    	||m_srcSushi->getIsJelly()||m_destSushi->getIsJelly()) {//gaoyu add for jelly not move
        m_movingVertical = true;
        return false;
    }
    
    Point posOfSrc = m_srcSushi->getPosition();
    Point posOfDest = m_destSushi->getPosition();
    float time = 0.2;
    
    // 1.swap in matrix
    m_matrix[m_srcSushi->getRow() * m_width + m_srcSushi->getCol()] = m_destSushi;
    m_matrix[m_destSushi->getRow() * m_width + m_destSushi->getCol()] = m_srcSushi;
    int tmpRow = m_srcSushi->getRow();
    int tmpCol = m_srcSushi->getCol();
    m_srcSushi->setRow(m_destSushi->getRow());
    m_srcSushi->setCol(m_destSushi->getCol());
    m_destSushi->setRow(tmpRow);
    m_destSushi->setCol(tmpCol);
    
    // 2.check for remove able
    std::list<CrushUnitSprite *> colChainListOfFirst;
    getColChain(m_srcSushi, colChainListOfFirst);
    
    std::list<CrushUnitSprite *> rowChainListOfFirst;
    getRowChain(m_srcSushi, rowChainListOfFirst);
    
    std::list<CrushUnitSprite *> colChainListOfSecond;
    getColChain(m_destSushi, colChainListOfSecond);
    
    std::list<CrushUnitSprite *> rowChainListOfSecond;
    getRowChain(m_destSushi, rowChainListOfSecond);
    
    if (colChainListOfFirst.size() >= 3
        || rowChainListOfFirst.size() >= 3
        || colChainListOfSecond.size() >= 3
        || rowChainListOfSecond.size() >= 3) {
        // just swap
        m_srcSushi->runAction(MoveTo::create(time, posOfDest));
        m_destSushi->runAction(MoveTo::create(time, posOfSrc));

        //gaoyu add  20150819
        m_needCreateJelly = true;
        return true;
    }
    
    if(m_srcSushi->getDisplayMode() == DISPLAY_MODE_ALL){
         m_srcSushi->runAction(MoveTo::create(time, posOfDest));
         m_destSushi->runAction(MoveTo::create(time, posOfSrc));
    	 m_allTargetSushi = m_destSushi;
         m_needCreateJelly = true;
         return true;
    }


    // 3.no chain, swap back
    m_matrix[m_srcSushi->getRow() * m_width + m_srcSushi->getCol()] = m_destSushi;
    m_matrix[m_destSushi->getRow() * m_width + m_destSushi->getCol()] = m_srcSushi;
    tmpRow = m_srcSushi->getRow();
    tmpCol = m_srcSushi->getCol();
    m_srcSushi->setRow(m_destSushi->getRow());
    m_srcSushi->setCol(m_destSushi->getCol());
    m_destSushi->setRow(tmpRow);
    m_destSushi->setCol(tmpCol);
    
    m_srcSushi->runAction(Sequence::create(
                                           MoveTo::create(time, posOfDest),
                                           MoveTo::create(time, posOfSrc),
                                           NULL));
    m_destSushi->runAction(Sequence::create(
                                            MoveTo::create(time, posOfSrc),
                                            MoveTo::create(time, posOfDest),
                                            NULL));
    return false;
}

void CrushView::update(float dt)
{
    // check if animationing
    if (m_isAnimationing) {
        // init with false
        m_isAnimationing = false;
        for (int i = 0; i < m_height * m_width; i++) {
            CrushUnitSprite *sushi = m_matrix[i];
            if (sushi && sushi->getNumberOfRunningActions() > 0) {
                m_isAnimationing = true;
                break;
            }
        }
    }
    
    // if sushi is moving, ignore use touch event
    m_isTouchEnable = !m_isAnimationing;
    
    if (!m_isAnimationing) {
        if (m_isNeedFillVacancies) {
            fillVacancies();
            m_isNeedFillVacancies = false;
        } else {
            if(!checkAndRemoveChain()){

            	if(m_combosNum >0){
                    if(m_combosNum >1){
                    	Size size = Director::getInstance()->getWinSize();
                    	CombosTextView *combos = CombosTextView::create(m_combosNum);
                    	combos->setPosition(size.width/2-80,-40);
                    	addChild(combos,10);
                    }
            		m_combosNum = 0;
            	}

            	checkJellyEatUnit();
            }
        }
    }
    
    suckCheckUpdate(dt);
    coverCloseCheck();
}


void CrushView::getColChain(CrushUnitSprite *sushi, std::list<CrushUnitSprite *> &chainList)
{
    chainList.push_back(sushi);// add first sushi
    
    int neighborCol = sushi->getCol() - 1;
    while (neighborCol >= 0) {
        CrushUnitSprite *neighborSushi = m_matrix[sushi->getRow() * m_width + neighborCol];
        if (neighborSushi
            && (neighborSushi->getImgIndex() == sushi->getImgIndex())
            && !neighborSushi->getIsNeedRemove()
            && !neighborSushi->getIgnoreCheck()) {
            chainList.push_back(neighborSushi);
            neighborCol--;
        } else {
            break;
        }
    }
    
    neighborCol = sushi->getCol() + 1;
    while (neighborCol < m_width) {
        CrushUnitSprite *neighborSushi = m_matrix[sushi->getRow() * m_width + neighborCol];
        if (neighborSushi
            && (neighborSushi->getImgIndex() == sushi->getImgIndex())
            && !neighborSushi->getIsNeedRemove()
            && !neighborSushi->getIgnoreCheck()) {
            chainList.push_back(neighborSushi);
            neighborCol++;
        } else {
            break;
        }
    }
}

void CrushView::getRowChain(CrushUnitSprite *sushi, std::list<CrushUnitSprite *> &chainList)
{
    chainList.push_back(sushi);// add first sushi
    
    int neighborRow = sushi->getRow() - 1;
    while (neighborRow >= 0) {
        CrushUnitSprite *neighborSushi = m_matrix[neighborRow * m_width + sushi->getCol()];
        if (neighborSushi
            && (neighborSushi->getImgIndex() == sushi->getImgIndex())
            && !neighborSushi->getIsNeedRemove()
            && !neighborSushi->getIgnoreCheck()) {
            chainList.push_back(neighborSushi);
            neighborRow--;
        } else {
            break;
        }
    }
    
    neighborRow = sushi->getRow() + 1;
    while (neighborRow < m_height) {
        CrushUnitSprite *neighborSushi = m_matrix[neighborRow * m_width + sushi->getCol()];
        if (neighborSushi
            && (neighborSushi->getImgIndex() == sushi->getImgIndex())
            && !neighborSushi->getIsNeedRemove()
            && !neighborSushi->getIgnoreCheck()) {
            chainList.push_back(neighborSushi);
            neighborRow++;
        } else {
            break;
        }
    }
}

void CrushView::fillVacancies()
{
    // reset moving direction flag
    m_movingVertical = true;
    m_isAnimationing = true;
    
    Size size = CCDirector::getInstance()->getWinSize();
    int *colEmptyInfo = (int *)malloc(sizeof(int) * m_width);
    memset((void *)colEmptyInfo, 0, sizeof(int) * m_width);
    
    // 1. drop exist sushi
    CrushUnitSprite *sushi = NULL;
    for (int col = 0; col < m_width; col++) {
        int removedSushiOfCol = 0;
        // from buttom to top
        for (int row = 0; row < m_height; row++) {
            sushi = m_matrix[row * m_width + col];
            if (NULL == sushi) {
            	removedSushiOfCol++;
            }else if(sushi->getIsBomb()&&(row == removedSushiOfCol)){
            	removedSushiOfCol++;
            	bombDropOut(row,col);
            }
            else {
                if (removedSushiOfCol > 0) {
                    // evey item have its own drop distance
                    int newRow = row - removedSushiOfCol;
                    int blankNum = 0;
                    if(m_matrix_blank[newRow * m_width + col]){
                    	blankNum = getBlankNum(newRow,col,row);
                    	if(removedSushiOfCol>blankNum){
                    		removedSushiOfCol -= blankNum;
                    		newRow += blankNum;
                    	}else{
                    		removedSushiOfCol = 0;
                    		continue;
                    	}
                    }
                    // switch in matrix
                    m_matrix[newRow * m_width + col] = sushi;
                    m_matrix[row * m_width + col] = NULL;
                    // move to new position
                    Point startPosition = sushi->getPosition();
                    Point endPosition = positionOfItem(newRow, col);
                    float speed = (startPosition.y - endPosition.y) / size.height;
                    sushi->stopAllActions();// must stop pre drop action
                    sushi->runAction(CCMoveTo::create(speed, endPosition));
                    // set the new row to item
                    sushi->setRow(newRow);
                }
            }
        }
        
        // record empty info
        colEmptyInfo[col] = removedSushiOfCol;
    }
    
    // 2. create new item and drop down.

    for (int col = 0; col < m_width; col++) {
        for (int row = m_height - colEmptyInfo[col]; row < m_height; row++) {
        	if((!m_matrix_blank[row * m_width + col])&&(!bombCreateCheck(row,col))){
        		createAndDropSushi(row, col);
        	}
        }
    }
    
    free(colEmptyInfo);
}

int CrushView::getBlankNum(int newRow, int col,int rowNow)
{
	int num = 0;
    for(int row=newRow;row < rowNow;row++,num++)
    {
    	if(!m_matrix_blank[row * m_width + col]){
    		return num;
    	}
    }
    return num;
}

bool CrushView::removeSushi()
{
	bool result = false;
    // make sequence remove
    m_isAnimationing = true;
    
    for (int i = 0; i < m_height * m_width; i++) {
        CrushUnitSprite *sushi = m_matrix[i];
        if (!sushi) {
            continue;
        }
        
        if(sushi->getIsBomb()){
        	continue;
        }

        if (sushi->getIsNeedRemove()) {
            m_isNeedFillVacancies = true;
            result = true;
            
            if(sushi->getDisplayMode() == DISPLAY_MODE_HORIZONTAL)
            {
                explodeSpecialH(sushi->getPosition());
            }
            else if (sushi->getDisplayMode() == DISPLAY_MODE_VERTICAL)
            {
                explodeSpecialV(sushi->getPosition());
            }
            else if (sushi->getDisplayMode() == DISPLAY_MODE_CIRCLE)
            {
                explodeSpecialO(sushi->getPosition());
            }
            explodeSushi(sushi);
            
        }
    }
    return result;
}

void CrushView::explodeSpecialH(Point point)
{
    Size size = Director::getInstance()->getWinSize();
    float scaleX = 4 ;
    float scaleY = 0.7 ;
    float time = 0.3;
    Point startPosition = point;
    float speed = 0.6f;
    
    auto colorSpriteRight = Sprite::create("colorHRight.png");
    addChild(colorSpriteRight, ZColorSprite);
    Point endPosition1 = Point(point.x - size.width, point.y);
    colorSpriteRight->setPosition(startPosition);
    colorSpriteRight->runAction(Sequence::create(ScaleTo::create(time, scaleX, scaleY),
                                                 MoveTo::create(speed, endPosition1),
                                                 CallFunc::create(CC_CALLBACK_0(Sprite::removeFromParent, colorSpriteRight)),
                                                 NULL));
    
    auto colorSpriteLeft = Sprite::create("colorHLeft.png");
    addChild(colorSpriteLeft, ZColorSprite);
    Point endPosition2 = Point(point.x + size.width, point.y);
    colorSpriteLeft->setPosition(startPosition);
    colorSpriteLeft->runAction(Sequence::create(ScaleTo::create(time, scaleX, scaleY),
                                                MoveTo::create(speed, endPosition2),
                                                CallFunc::create(CC_CALLBACK_0(Sprite::removeFromParent, colorSpriteLeft)),
                                                NULL));
    
    
}

void CrushView::explodeSpecialV(Point point)
{
    Size size = Director::getInstance()->getWinSize();
    float scaleY = 4 ;
    float scaleX = 0.7 ;
    float time = 0.3;
    Point startPosition = point;
    float speed = 0.6f;
    
    auto colorSpriteDown = Sprite::create("colorVDown.png");
    addChild(colorSpriteDown, ZColorSprite);
    Point endPosition1 = Point(point.x , point.y - size.height);
    colorSpriteDown->setPosition(startPosition);
    colorSpriteDown->runAction(Sequence::create(ScaleTo::create(time, scaleX, scaleY),
                                                MoveTo::create(speed, endPosition1),
                                                CallFunc::create(CC_CALLBACK_0(Sprite::removeFromParent, colorSpriteDown)),
                                                NULL));
    
    auto colorSpriteUp = Sprite::create("colorVUp.png");
    addChild(colorSpriteUp, ZColorSprite);
    Point endPosition2 = Point(point.x , point.y + size.height);
    colorSpriteUp->setPosition(startPosition);
    colorSpriteUp->runAction(Sequence::create(ScaleTo::create(time, scaleX, scaleY),
                                              MoveTo::create(speed, endPosition2),
                                              CallFunc::create(CC_CALLBACK_0(Sprite::removeFromParent, colorSpriteUp)),
                                              NULL));
}

void CrushView::explodeSpecialO(Point point)
{

}

void CrushView::actionEndCallback(Node *node)
{
    CrushUnitSprite *sushi = (CrushUnitSprite *)node;
    if(sushi){
        m_matrix[sushi->getRow() * m_width + sushi->getCol()] = NULL;
        sushi->removeFromParent();
    }

}

void CrushView::explodeSushi(CrushUnitSprite *sushi)
{
    float time = 0.3;
    
    // 1. action for sushi
    sushi->runAction(Sequence::create(
                                      ScaleTo::create(time, 0.0),
                                      CallFuncN::create(CC_CALLBACK_1(CrushView::actionEndCallback, this)),
                                      NULL));
    
    // 2. action for circle
    auto circleSprite = Sprite::create("circle.png");
    addChild(circleSprite, ZColorSprite);
    circleSprite->setPosition(sushi->getPosition());
    circleSprite->setScale(0);// start size
    circleSprite->runAction(Sequence::create(ScaleTo::create(time, 1.0),
                                             CallFunc::create(CC_CALLBACK_0(Sprite::removeFromParent, circleSprite)),
                                             NULL));
    
    // 3. particle effect
    auto particleStars = ParticleSystemQuad::create("stars.plist");
    particleStars->setAutoRemoveOnFinish(true);
    particleStars->setBlendAdditive(false);
    particleStars->setPosition(sushi->getPosition());
    particleStars->setScale(0.3);
    addChild(particleStars, ZStar);
    
    //add for bad state remove do
    if(m_matrix_bad[sushi->getRow() * m_width + sushi->getCol()]){
    	BadStateUnitSprite *badState = m_matrix_bad[sushi->getRow() * m_width + sushi->getCol()];
    	badState->runAction(Sequence::create( ScaleTo::create(time, 0.0),
    	                                      CallFunc::create(CC_CALLBACK_0(Sprite::removeFromParent, badState)),
    	                                      NULL));
    	m_matrix_bad[sushi->getRow() * m_width + sushi->getCol()] = NULL;
    }

    //add for bad up state remove do
    if(m_matrix_bad_up[sushi->getRow() * m_width + sushi->getCol()]){
        BadStateUnitSprite *badStateUp = m_matrix_bad_up[sushi->getRow() * m_width + sushi->getCol()];
        badStateUp->runAction(Sequence::create( ScaleTo::create(time, 0.0),
        	                                  CallFunc::create(CC_CALLBACK_0(Sprite::removeFromParent, badStateUp)),
        	                                  NULL));
        m_matrix_bad_up[sushi->getRow() * m_width + sushi->getCol()] = NULL;
    }
    crushCoverCheck(sushi->getRow(), sushi->getCol());
    //gaoyu add for jelly explode
    crushJellyCheck(sushi->getRow(), sushi->getCol());
}

bool CrushView::checkAndRemoveChain()
{
    CrushUnitSprite *sushi;
    // 1. reset ingnore flag
    for (int i = 0; i < m_height * m_width; i++) {
        sushi = m_matrix[i];
        if (!sushi) {
            continue;
        }
        sushi->setIgnoreCheck(false);
    }
    
    if(m_allTargetSushi){
    	markRemove(m_srcSushi);
    	afterChainRemoveDo(m_srcSushi);
    	m_allTargetSushi = NULL;
    }

    // 2. check chain
    for (int i = 0; i < m_height * m_width; i++) {
        sushi = m_matrix[i];

        if (!sushi) {
            continue;
        }

        if(sushi->getIsJelly()){//gaoyu add for jelly not crush
        	continue;
        }
        
        if (sushi->getIsNeedRemove()) {
            continue;
        }
        if (sushi->getIgnoreCheck()) {
            continue;
        }
        
        // start count chain
        std::list<CrushUnitSprite *> colChainList;
        getColChain(sushi, colChainList);
        
        std::list<CrushUnitSprite *> rowChainList;
        getRowChain(sushi, rowChainList);
        
        std::list<CrushUnitSprite *> &longerList = colChainList.size() > rowChainList.size() ? colChainList : rowChainList;
        if (longerList.size() < 3) {
            continue;
        }
        
        std::list<CrushUnitSprite *>::iterator itList;
        bool isSetedIgnoreCheck = false;
        bool isSetedIgnoreCheckAll = false;
        if(!checkHasCircle(colChainList,rowChainList)){
        	for (itList = longerList.begin(); itList != longerList.end(); itList++) {
				sushi = (CrushUnitSprite *)*itList;
				if (!sushi) {
					continue;
				}
                if (longerList.size() > 4){
					if (sushi == m_srcSushi || sushi == m_destSushi) {
						isSetedIgnoreCheckAll = true;
						sushi->setIgnoreCheck(true);
						sushi->setIsNeedRemove(false);
						sushi->setDisplayMode(DISPLAY_MODE_ALL);
						continue;
					}
                }else if (longerList.size() > 3) {
					if (sushi == m_srcSushi || sushi == m_destSushi) {
						isSetedIgnoreCheck = true;
						sushi->setIgnoreCheck(true);
						sushi->setIsNeedRemove(false);
						sushi->setDisplayMode(m_movingVertical ? DISPLAY_MODE_VERTICAL : DISPLAY_MODE_HORIZONTAL);
						continue;
					}
				}
				markRemove(sushi);
			}

			if (!isSetedIgnoreCheckAll && longerList.size() > 4) {
				sushi->setIgnoreCheck(true);
				sushi->setIsNeedRemove(false);
				sushi->setDisplayMode(DISPLAY_MODE_ALL);
			}else if (!isSetedIgnoreCheck && longerList.size() > 3) {
				sushi->setIgnoreCheck(true);
				sushi->setIsNeedRemove(false);
				sushi->setDisplayMode(m_movingVertical ? DISPLAY_MODE_VERTICAL : DISPLAY_MODE_HORIZONTAL);
			}

			//add for attack
			afterChainRemoveDo(sushi);
        }
    }
    
    return removeSushi();
}

void CrushView::afterChainRemoveDo(CrushUnitSprite *sushi)
{
	m_crushType = sushi->getAttackType();
	m_combosNum++;
	_callback(this);

	int playNum = m_combosNum<13?m_combosNum:12;
	MusicController::getInstance()->effectPlay(
			__String::createWithFormat("combo_sound%d.ogg",playNum)->getCString());
}

void CrushView::markRemove(CrushUnitSprite *sushi)
{
    if (sushi->getIsNeedRemove()) {
        return;
    }
    if (sushi->getIgnoreCheck()) {
        return;
    }
    
    // mark self
    sushi->setIsNeedRemove(true);
    // check for type and mark for certical neighbour
    if (sushi->getDisplayMode() == DISPLAY_MODE_VERTICAL) {
        for (int row = 0; row < m_height; row++) {
            CrushUnitSprite *tmp = m_matrix[row * m_width + sushi->getCol()];
            if (!tmp || tmp == sushi) {
                continue;
            }
            
            if (tmp->getDisplayMode() == DISPLAY_MODE_NORMAL) {
                tmp->setIsNeedRemove(true);
            } else {
                markRemove(tmp);
            }
        }
        // check for type and mark for horizontal neighbour
    } else if (sushi->getDisplayMode() == DISPLAY_MODE_HORIZONTAL) {
        for (int col = 0; col < m_width; col++) {
            CrushUnitSprite *tmp = m_matrix[sushi->getRow() * m_width + col];
            if (!tmp || tmp == sushi) {
                continue;
            }
            
            if (tmp->getDisplayMode() == DISPLAY_MODE_NORMAL) {
                tmp->setIsNeedRemove(true);
            } else {
                markRemove(tmp);
            }
        }
    }else if (sushi->getDisplayMode() == DISPLAY_MODE_CIRCLE) {
        for (int col = sushi->getCol()-1; col < sushi->getCol()+2; col++) {
        	for(int row = sushi->getRow()-1; row < sushi->getRow()+2; row++){
        		if((col<0)||(row<0))
        			continue;
        		if((col>m_width-1)&&(row>m_height-1))
        			continue;
                CrushUnitSprite *tmp = m_matrix[row * m_width + col];
                if (!tmp || tmp == sushi) {
                    continue;
                }

                if (tmp->getDisplayMode() == DISPLAY_MODE_NORMAL) {
                    tmp->setIsNeedRemove(true);
                } else {
                    markRemove(tmp);
                }
        	}

        }
    }else if (sushi->getDisplayMode() == DISPLAY_MODE_ALL) {
    	CrushUnitSprite *sushiEx = (m_allTargetSushi!=NULL)?m_allTargetSushi:CrushUnitSprite::create(0, 0);//ramdom create one
        for (int i = 0; i < m_height * m_width; i++) {
        	CrushUnitSprite *tmp = m_matrix[i];
            if (!tmp || tmp == sushi) {
                continue;
            }
            if(sushiEx->getImgIndex() == tmp->getImgIndex()){
                if (tmp->getDisplayMode() == DISPLAY_MODE_NORMAL) {
                    tmp->setIsNeedRemove(true);
                } else {
                    markRemove(tmp);
                }
            }
        }

    }
}

void CrushView::initMatrix(bool* data)
{
	if(data){
	    for (int row = 0; row < m_height; row++) {
	        for (int col = 0; col < m_width; col++) {
	        	if(data[row * m_width + col]
	        	   &&(!m_matrix_blank[row * m_width + col])){
	        		createJelly(row,col);
	        	}
	        }
	    }
	}


    for (int row = 0; row < m_height; row++) {
        for (int col = 0; col < m_width; col++) {
        	if(m_matrix[row * m_width + col]==NULL
        	   &&(!m_matrix_blank[row * m_width + col])){
        		createAndDropSushi(row, col);
        	}
        }
    }
}

void CrushView::createAndDropSushi(int row, int col)
{
    Size size = Director::getInstance()->getWinSize();
    
    CrushUnitSprite *sushi = CrushUnitSprite::create(row, col);
    
    // create animation
    Point endPosition = positionOfItem(row, col);
    //Point startPosition = Point(endPosition.x, endPosition.y + size.height / 2);
    Point startPosition = Point(endPosition.x, endPosition.y + DROP_HEIGHT);
    
    sushi->setPosition(startPosition);
    //float speed = startPosition.y / (1.5 * size.height);
    float speed = (startPosition.y - endPosition.y) / size.height;
    sushi->runAction(MoveTo::create(speed, endPosition));
    // add to BatchNode
    spriteSheet->addChild(sushi);
    
    m_matrix[row * m_width + col] = sushi;
}

Point CrushView::positionOfItem(int row, int col)
{
    float x = m_matrixLeftBottomX + (CrushUnitSprite::getContentWidth() + SUSHI_GAP) * col + CrushUnitSprite::getContentWidth() / 2;
    float y = m_matrixLeftBottomY + (CrushUnitSprite::getContentWidth() + SUSHI_GAP) * row + CrushUnitSprite::getContentWidth() / 2;
    return Point(x, y);
}

void CrushView::setCallback(const crushViewCallback& callback)
{
    _callback = callback;
}

void CrushView::setBadCallback(const crushViewBadStateCallback& callback)
{
    _badCallback = callback;
}

void CrushView::setCoverCallback(const crushViewCoverCloseCallback& callback)
{
	_coverCallback = callback;
}

void CrushView::setPause(bool pause)
{
    m_isPause = pause;
}

void CrushView::initMatrixBad(bool* data)
{
    for (int row = 0; row < m_height; row++) {
        for (int col = 0; col < m_width; col++) {
        	if(data[row * m_width + col]){
        		createBadState(row, col);
        	}
        }
    }
}

void CrushView::createBadState(int row, int col)
{
    BadStateUnitSprite *badState = BadStateUnitSprite::create(row, col, BadStateTypeSuckBlood);
    Point endPosition = positionOfItem(row, col);
    badState->setPosition(endPosition);
    spriteSheetBad->addChild(badState);
    m_matrix_bad[row * m_width + col] = badState;
}

int CrushView::getBadStateNum()
{
    int result = 0;
    for (int row = 0; row < m_height; row++) {
        for (int col = 0; col < m_width; col++) {
            if(m_matrix_bad[row * m_width + col]){
                result++;
            }
        }
    }
    return result;
}

void CrushView::suckCheckUpdate(float dt)
{
    //add suck do
    if(m_badStateLastTime < SUCK_BLOOD_TIME){
        m_badStateLastTime +=dt;
    }else{
        m_badStateLastTime = 0;
        m_suckNum = getBadStateNum()*SUCK_BLOOD_NUM;
        if(m_suckNum > 0){
        	_badCallback(this);
        }
    }
}

void CrushView::initMatrixBadUp(bool* data)
{
    for (int row = 0; row < m_height; row++) {
        for (int col = 0; col < m_width; col++) {
        	if(data[row * m_width + col]){
        		createBadUpState(row, col);
        	}
        }
    }
}

void CrushView::createBadUpState(int row, int col)
{
    BadStateUnitSprite *badState = BadStateUnitSprite::create(row, col, BadStateTypeMonsterHand);
    Point endPosition = positionOfItem(row, col);
    badState->setPosition(endPosition);
    spriteSheetBadUp->addChild(badState);
    m_matrix_bad_up[row * m_width + col] = badState;
}

bool CrushView::isHandByMonster(int row, int col)
{
	if(m_matrix_bad_up[row * m_width + col]){
		return true;
	}
	return false;
}

void CrushView::createJelly(int row, int col)
{
	CrushUnitSprite *sushi = CrushUnitSprite::createJelly(row, col);
    Point endPosition = positionOfItem(row, col);
    sushi->setPosition(endPosition);
    spriteSheet->addChild(sushi);
    m_matrix[row * m_width + col] = sushi;
}

void CrushView::checkJellyEatUnit()
{
	if(m_needCreateJelly == true){
		m_needCreateJelly = false;
		__Array *arrayJelly = getAllCanEatJelly();
		if(arrayJelly->count()){
			int index = CCRANDOM_0_1() * arrayJelly->count();
			CrushUnitSprite *jelly = (CrushUnitSprite *)arrayJelly->getObjectAtIndex(index);
			JellyEatTarget(jelly->getRow(), jelly->getCol());
		}

	}
}

__Array* CrushView::getAllCanEatJelly()
{
	__Array *array = __Array::createWithCapacity(55);
    for (int row = 0; row < m_height; row++) {
        for (int col = 0; col < m_width; col++) {
            if((m_matrix[(row) * m_width + col])&&
            	((CrushUnitSprite *)(m_matrix[(row) * m_width + col]))->getIsJelly() == true ){
                if(isJellyHasEatTarget(row,col)){
                    array->addObject(m_matrix[row * m_width + col]);
                }
            }
        }
    }
    return array;
}

bool CrushView::isJellyHasEatTarget(int row, int col)
{
	if(row >= 1){
		if((m_matrix[(row-1) * m_width + col])
			&&((CrushUnitSprite *)(m_matrix[(row-1) * m_width + col]))->getIsJelly() == false
			&&((CrushUnitSprite *)(m_matrix[(row-1) * m_width + col]))->getIsBomb() == false){
            return true;
		}
	}

	if(row < m_height-1){
		if((m_matrix[(row+1) * m_width + col])
			&&((CrushUnitSprite *)(m_matrix[(row+1) * m_width + col]))->getIsJelly() == false
			&&((CrushUnitSprite *)(m_matrix[(row+1) * m_width + col]))->getIsBomb() == false){
            return true;
		}
	}

	if(col >= 1){
		if((m_matrix[(row) * m_width + (col-1)])
			&&((CrushUnitSprite *)(m_matrix[(row) * m_width + (col-1)]))->getIsJelly() == false
			&&((CrushUnitSprite *)(m_matrix[(row) * m_width + (col-1)]))->getIsBomb() == false){
            return true;
		}
	}

	if(col < m_width - 1){
		if((m_matrix[(row) * m_width + (col+1)])
			&&((CrushUnitSprite *)(m_matrix[(row) * m_width + (col+1)]))->getIsJelly() == false
			&&((CrushUnitSprite *)(m_matrix[(row) * m_width + (col+1)]))->getIsBomb() == false){
            return true;
		}
	}
	return false;

}

void CrushView::JellyEatTarget(int row, int col)
{
	__Array *array = __Array::create();
	if(row >= 1){
		if((m_matrix[(row-1) * m_width + col])
			&&((CrushUnitSprite *)(m_matrix[(row-1) * m_width + col]))->getIsJelly() == false
			&&((CrushUnitSprite *)(m_matrix[(row-1) * m_width + col]))->getIsBomb() == false){
            array->addObject((CrushUnitSprite *)m_matrix[(row-1) * m_width + col]);
		}
	}

	if(row < m_height-1){
		if((m_matrix[(row+1) * m_width + col])
			&&((CrushUnitSprite *)(m_matrix[(row+1) * m_width + col]))->getIsJelly() == false
			&&((CrushUnitSprite *)(m_matrix[(row+1) * m_width + col]))->getIsBomb() == false){
			array->addObject((CrushUnitSprite *)m_matrix[(row+1) * m_width + col]);
		}
	}

	if(col >= 1){
		if((m_matrix[(row) * m_width + (col-1)])
			&&((CrushUnitSprite *)(m_matrix[(row) * m_width + (col-1)]))->getIsJelly() == false
			&&((CrushUnitSprite *)(m_matrix[(row) * m_width + (col-1)]))->getIsBomb() == false){
			array->addObject((CrushUnitSprite *)m_matrix[(row) * m_width + (col-1)]);
		}
	}

	if(col < m_width - 1){
		if((m_matrix[(row) * m_width + (col+1)])
			&&((CrushUnitSprite *)(m_matrix[(row) * m_width + (col+1)]))->getIsJelly() == false
			&&((CrushUnitSprite *)(m_matrix[(row) * m_width + (col+1)]))->getIsBomb() == false){
			array->addObject((CrushUnitSprite *)m_matrix[(row) * m_width + (col+1)]);
		}
	}

	if(array->count()){
		int index = CCRANDOM_0_1() * array->count();
		CrushUnitSprite *sushi = (CrushUnitSprite *)array->getObjectAtIndex(index);
		float time = 0.3;
	    sushi->runAction(Sequence::create(
	                                      ScaleTo::create(time, 0.0),
	                                      NULL));

		CrushUnitSprite *jelly = CrushUnitSprite::createJelly(sushi->getRow(), sushi->getCol());
	    Point endPosition = positionOfItem(sushi->getRow(), sushi->getCol());
	    jelly->setPosition(endPosition);
	    jelly->setScale(0.0);
	    spriteSheet->addChild(jelly);
	    jelly->runAction(Sequence::create(
	                                      ScaleTo::create(time, 1.0),
	                                      CallFuncN::create(CC_CALLBACK_1(CrushView::jellyEatEndCallback, this)),
	                                      NULL));
	}
}

void CrushView::jellyEatEndCallback(Node *node)
{
    CrushUnitSprite *jelly = (CrushUnitSprite *)node;
    CrushUnitSprite *sushi = (CrushUnitSprite *)m_matrix[jelly->getRow() * m_width + jelly->getCol()];
    sushi->removeFromParent();
    m_matrix[jelly->getRow() * m_width + jelly->getCol()] = jelly;
}

void CrushView::explodeJelly(int row,int col)
{
	CrushUnitSprite *jelly = (CrushUnitSprite *)m_matrix[row * m_width + col];
	float time = 0.3;

	// 1. action for circle
	auto circleSprite = Sprite::create("circle.png");
	addChild(circleSprite, ZColorSprite);
	circleSprite->setPosition(jelly->getPosition());
	circleSprite->setScale(0);// start size
	circleSprite->runAction(Sequence::create(ScaleTo::create(time, 1.0),
	                                             CallFunc::create(CC_CALLBACK_0(Sprite::removeFromParent, circleSprite)),
	                                             NULL));

	// 2. particle effect
	auto particleStars = ParticleSystemQuad::create("stars.plist");
	particleStars->setAutoRemoveOnFinish(true);
	particleStars->setBlendAdditive(false);
	particleStars->setPosition(jelly->getPosition());
	particleStars->setScale(0.3);
	addChild(particleStars, ZStar);

	// 3
	jelly->runAction(Sequence::create(
	                                  ScaleTo::create(time, 0.0),
	                                  CallFuncN::create(CC_CALLBACK_0(Sprite::removeFromParent, jelly)),
	                                  NULL));
	m_matrix[row * m_width + col] = NULL;
    m_needCreateJelly = false;//if explode jelly then not create again

}

void CrushView::crushJellyCheck(int row, int col)
{
	if(row >= 1){
		if(m_matrix[(row-1) * m_width + col]){
			if(((CrushUnitSprite *)(m_matrix[(row-1) * m_width + col]))->getIsJelly() == true)
				explodeJelly(row-1,col);
		}
	}

	if(row < m_height-1){
		if(m_matrix[(row+1) * m_width + col]){
			if(((CrushUnitSprite *)(m_matrix[(row+1) * m_width + col]))->getIsJelly() == true)
			    explodeJelly(row+1,col);
		}
	}

	if(col >= 1){
		if(m_matrix[(row) * m_width + (col-1)]){
			if(((CrushUnitSprite *)(m_matrix[(row) * m_width + (col-1)]))->getIsJelly() == true)
			    explodeJelly(row,col-1);
		}
	}

	if(col < m_width - 1){
		if(m_matrix[(row) * m_width + (col+1)]){
			if(((CrushUnitSprite *)(m_matrix[(row) * m_width + (col+1)]))->getIsJelly() == true)
			    explodeJelly(row,col+1);
		}
	}
}

void CrushView::bossCreateJellys()
{
    int row = 5;
    for(int col = 0; col < m_width; col++){
    	bossCreateJelly(row,col);
    }
}

void CrushView::bossCreateJelly(int row, int col)
{
	if(((CrushUnitSprite *)(m_matrix[(row) * m_width + (col)]))->getIsJelly() == true)
		return;
	float time = 0.3;
	if(m_matrix[(row) * m_width + (col)]){
		CrushUnitSprite *sushi = (CrushUnitSprite *)(m_matrix[(row) * m_width + (col)]);
		sushi->runAction(Sequence::create(ScaleTo::create(time, 0.0),
				CallFunc::create(CC_CALLBACK_0(Sprite::removeFromParent, sushi)),
		                                      NULL));
	}

	CrushUnitSprite *jelly = CrushUnitSprite::createJelly(row, col);
    Point endPosition = positionOfItem(row, col);
    jelly->setPosition(endPosition);
    spriteSheet->addChild(jelly);
    m_matrix[row * m_width + col] = jelly;
    //action
    jelly->setScale(0.0);
    jelly->runAction(Sequence::create(ScaleTo::create(time, 1.0),
    	                              NULL));
}

void CrushView::createAndDropBomb(int row, int col)
{
    Size size = Director::getInstance()->getWinSize();

    CrushUnitSprite *bomb = CrushUnitSprite::createBomb(row, col);

    // create animation
    Point endPosition = positionOfItem(row, col);
    Point startPosition = Point(endPosition.x, endPosition.y + DROP_HEIGHT);

    bomb->setPosition(startPosition);
    float speed = (startPosition.y - endPosition.y) / size.height;
    bomb->runAction(MoveTo::create(speed, endPosition));
    // add to BatchNode
    spriteSheet->addChild(bomb);
    m_matrix[row * m_width + col] = bomb;
}

bool CrushView::isThereHasBomb()
{
    for (int row = 0; row < m_height; row++) {
        for (int col = 0; col < m_width; col++) {
        	if(!m_matrix[(row) * m_width + col]) continue;

            if(((CrushUnitSprite *)(m_matrix[(row) * m_width + col]))->getIsBomb() == true ){
                return true;
            }
        }
    }
    return false;
}

void CrushView::bombDropOut(int row, int col)
{
	Size size = CCDirector::getInstance()->getWinSize();
	CrushUnitSprite *sushi = m_matrix[row * m_width + col];
	m_matrix[row * m_width + col] = NULL;
	Point startPosition = sushi->getPosition();
	Point endPosition = positionOfItem(-1, col);
	float speed = (startPosition.y - endPosition.y) / size.height;
	sushi->stopAllActions();// must stop pre drop action
	sushi->runAction(Sequence::create(CCMoveTo::create(speed, endPosition),
	        CallFunc::create(CC_CALLBACK_0(Sprite::removeFromParent, sushi)),
	        		                           NULL));
	m_crushType = sushi->getAttackType();
	_callback(this);
}

bool CrushView::bombCreateCheck(int row, int col)
{
	int percent = CCRANDOM_0_1()*100;
	if((m_bombNum > 0)&&(row ==  m_height - 1)
		&&(percent < BOMB_OUT_PERCENT)&&(!isThereHasBomb())){
    	createAndDropBomb(row, col);
    	m_bombNum--;
    	return true;
	}
	return false;
}

void CrushView::initMatrixProtectCover(bool* data)
{
	if(!data) return;
	m_isCoverNeedClose = true;

    for (int row = 0; row < m_height; row++) {
        for (int col = 0; col < m_width; col++) {
        	if(data[row * m_width + col]){
        		createProtectCover(row, col);
        	}
        }
    }
}

void CrushView::createProtectCover(int row, int col)
{
    BadStateUnitSprite *cover = BadStateUnitSprite::create(row, col, BadStateTypeProtectCover);
    Point endPosition = positionOfItem(row, col);
    cover->setPosition(endPosition);
    spriteSheetProtectCover->addChild(cover);
    m_matrix_protect_cover[row * m_width + col] = cover;
}

void CrushView::crushCoverCheck(int row, int col)
{
	float time = 0.3;
    if(m_matrix_protect_cover[row * m_width + col]){
        BadStateUnitSprite *cover = m_matrix_protect_cover[row * m_width + col];
        cover->runAction(Sequence::create( ScaleTo::create(time, 0.0),
        	                                  CallFunc::create(CC_CALLBACK_0(Sprite::removeFromParent, cover)),
        	                                  NULL));
        m_matrix_protect_cover[row * m_width + col] = NULL;
    }
}

void CrushView::coverCloseCheck()
{
    if(m_isCoverNeedClose)
    {
        for (int row = 0; row < m_height; row++) {
            for (int col = 0; col < m_width; col++) {
            	if(m_matrix_protect_cover[row * m_width + col]){
            		return;
            	}
            }
        }
        _coverCallback(this);
        m_isCoverNeedClose = false;
    }
}

void CrushView::initMatrixBlank(bool* data)
{
	if(!data) return;

    for (int row = 0; row < m_height; row++) {
        for (int col = 0; col < m_width; col++) {
        	if(data[row * m_width + col]){
        		createBlank(row, col);
        	}
        }
    }
}

void CrushView::createBlank(int row, int col)
{
    BadStateUnitSprite *blank = BadStateUnitSprite::create(row, col, BadStateTypeBlank);
    Point endPosition = positionOfItem(row, col);
    blank->setPosition(endPosition);
    spriteSheetBlank->addChild(blank);
    m_matrix_blank[row * m_width + col] = blank;
}

bool CrushView::checkHasCircle(std::list<CrushUnitSprite *> &colChainList,
                               std::list<CrushUnitSprite *> &rowChainList)
{
	bool result = false;
	CrushUnitSprite *sushi;
    std::list<CrushUnitSprite *>::iterator itList;
    if((colChainList.size()>2)&&(rowChainList.size()>2)){
    	itList = rowChainList.begin();
    	sushi = (CrushUnitSprite *)*itList;
    	circleMarkRemove(colChainList,rowChainList);
    	result = true;
    }else if(colChainList.size()>2){
    	for (itList = colChainList.begin(); itList != colChainList.end(); itList++){
    		sushi = (CrushUnitSprite *)*itList;
            std::list<CrushUnitSprite *> rowChainListEx;
            getRowChain(sushi, rowChainListEx);
            if(rowChainListEx.size()>2){
            	circleMarkRemove(colChainList,rowChainListEx);
            	result = true;
            	break;
            }
    	}
    }else if(rowChainList.size()>2){
    	for (itList = rowChainList.begin(); itList != rowChainList.end(); itList++){
    		sushi = (CrushUnitSprite *)*itList;
            std::list<CrushUnitSprite *> colChainListEx;
            getColChain(sushi, colChainListEx);
            if(colChainListEx.size()>2){
            	circleMarkRemove(colChainListEx,rowChainList);
            	result = true;
            	break;
            }
    	}
    }

    if(result&&(sushi)){
    	afterChainRemoveDo(sushi);
    }
    return result;
}

void CrushView::circleMarkRemove(std::list<CrushUnitSprite *> &colChainList,
		                         std::list<CrushUnitSprite *> &rowChainList)
{
	bool isSetedIgnoreCheck = false;
	CrushUnitSprite *sushi;
	std::list<CrushUnitSprite *>::iterator itList;
	std::list<CrushUnitSprite *> &circleList = colChainList;
	for (itList = rowChainList.begin(); itList != rowChainList.end(); itList++){
		sushi = (CrushUnitSprite *)*itList;
		circleList.push_back(sushi);
	}
	for (itList = circleList.begin(); itList != circleList.end(); itList++) {
		sushi = (CrushUnitSprite *)*itList;
		if (!sushi) {
			continue;
		}
		if (sushi == m_srcSushi || sushi == m_destSushi) {
			isSetedIgnoreCheck = true;
			sushi->setIgnoreCheck(true);
			sushi->setIsNeedRemove(false);
			sushi->setDisplayMode(DISPLAY_MODE_CIRCLE);
			continue;
		}

		markRemove(sushi);
	}
	//if circle not switch create, set last one is circle model
	if (!isSetedIgnoreCheck) {
		sushi->setIgnoreCheck(true);
		sushi->setIsNeedRemove(false);
		sushi->setDisplayMode(DISPLAY_MODE_CIRCLE);
	}
}

